const { logInfo, logStep } = require("../../util/logInfo");
const {
    SyncHook,//同步钩子， 全部执行，无返回值
    SyncBailHook,//同步熔断钩子，有一个返回值不为undefined即结束
    AsyncParallelHook,//异步钩子，全部执行，第一个执行完成后就会回调，有返回值
    AsyncSeriesHook//串行异步，全部执行，无返回值
} = require('tapable')
const webpack = require('./index');
const Compilation = require("./Compilation");

class Compiler {
    constructor(context) {
        logInfo('Object.freeze 冻结一个对象, 包含所有钩子函数')
        this.hooks = Object.freeze({
            initialize: new SyncHook([]),
            shouldEmit: new SyncBailHook(['compilation']),
            beforeRun: new AsyncSeriesHook(['comipiler']),
            afterDone: new SyncHook(["stats"]),
            failed: new SyncHook(["error"]),
            beforeCompile: new AsyncSeriesHook(["params"]),
            compile: new SyncHook(["params"]),
            make: new AsyncParallelHook(["compilation"]),
            run: new AsyncSeriesHook(["compiler"]),
            finishMake: new AsyncSeriesHook(["compilation"]),
            afterCompile: new AsyncSeriesHook(["compilation"]),
        })

        this.webpack = webpack;

    }
    watch() {

    }
    run(callback) {
        if (this.running) {
            return callback('重复了， 亲')
        }
        let logger;
        const finalCallback = (err, stats) => {
            if (err) {
                this.hooks.failed.call(err);
            }
            if (callback != undefined) callback(err, stats);
            this.hooks.afterDone.call(stats);
        }

        this.running = true;

        const onCompiled = (errm, compilation) => {

        }

        const run = () => {
            logStep('从这里可以看出钩子的执行顺序：beforeRun->')
            this.hooks.beforeRun.callAsync(this, err => {
                if (err) return finalCallback(err);
                this.hooks.run.callAsync(this, err => {
                    if (err) return finalCallback(err);
                    this.readRecords((err) => {
                        if (err) return finalCallback(err)
                        logStep('compile')
                        this.compile(onCompiled)
                    })
                })
            })
        }
        run();
    }

    compile(callback) {
        const params = {};
        logStep('beforeCompile')
        this.hooks.beforeCompile.callAsync(params, err => {
            if (err) return callback(err)
            this.hooks.compile.call(params);
            const compilation = this.newCompilation(params);

            logStep('make')
            this.hooks.make.callAsync(compilation, err => {
                if (err) return callback(err);
                logStep('finishMake')
                this.hooks.finishMake.callAsync(compilation, err => {
                    if (err) return callback(err);
                    process.nextTick(() => {
                        logStep('finish')
                        compilation.finish((err) => {
                            logStep('seal')
                            compilation.seal(err => {
                                logStep('afterCompile')
                                this.hooks.afterCompile.call(compilation, err => {
                                    callback(null, compilation)
                                })
                            })
                        })
                    })
                })
            })
        })
    }

    newCompilation(params) {
        const compilation = this.createCompilation();
        return compilation;
    }
    createCompilation() {
        return new Compilation(this);
    }

    readRecords(callback) {
        callback();
    }
    close() {

    }
}
module.exports = Compiler;